﻿using System;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Mvc.XForms.Controls.Formatters;
using Mvc.XForms.Controls.Settings;

namespace Mvc.XForms.Controls {
	public class XForm<TContext> : XFormContextBase<TContext, TContext>, IXForm<TContext> {
		public XFormSettings<TContext> Settings { get; private set; }
		public ModelStateDictionary ModelState { get; set; }
		public HttpContextBase HttpContext { get; set; }
		public FormCollection FormCollection { get; set; }
		public IFormatter Formatter { get; set; }
		public ISubmission DefaultSubmission { get; set; }
		public Action<IXForm<TContext>> Form { get; set; }
		public HtmlHelper HtmlHelper { get; set; }

		public override XFormControlType ControlType {
			get { return XFormControlType.XForm; }
		}

		public XForm(HttpContextBase httpContext, ModelStateDictionary modelState, TContext model)
			: this(httpContext, modelState, model, null) { }

		public XForm(HttpContextBase httpContext, ModelStateDictionary modelState, TContext model, HtmlHelper htmlHelper)
			: base(null, null) {
			if (model == null)
				throw new ArgumentNullException("model");

			Settings = new XFormSettings<TContext>(this);
			CssClass.Add("xform");

			HtmlHelper = htmlHelper;
			HttpContext = httpContext;
			ModelState = modelState;
			XForm = this;
			ModelContext = model;
			Formatter = FormatterFactory.Current.Formatter;
			DefaultSubmission = new Submission();
			SetChildAsInRepeatTemplate = true;
		}

		public override void Render() {
			ApplySettingsOrDefaults();

			var resp = XForm.HttpContext.Response;
			OutputForm(resp);
			OutputScriptBlock(resp);
		}

		public virtual void ApplySettingsOrDefaults() {
			var req = HttpContext.Request;
			var formCollection = DefaultSubmission.Method == SubmissionMethod.Get ? req.QueryString : req.Form;
			FormCollection = new FormCollection(formCollection);
		}

		public virtual void OutputForm(HttpResponseBase resp) {
			var xformBegin = Formatter.XFormBegin(this);
			var xformEnd = Formatter.XFormEnd(this);

			resp.Write(xformBegin);
			Form(this);
			resp.Write(xformEnd);
		}

		public virtual void OutputScriptBlock(HttpResponseBase resp) {
			var xformScript = Formatter.XFormScript(this);
			resp.Write(xformScript);
		}

		public override object ToJson() {
			var controlsJson = Controls
				.Select(con => con.ToJson())
				.Where(obj => obj != null)
				.ToList();

			return new {
				id = ClientID ?? string.Empty,
				cons = controlsJson
			};
		}
	}
}